#pragma once
#include "err.hpp"
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h> // struct sockaddr_in
#include <arpa/inet.h> // s+truct sockaddr_in
#include <cerrno>
#include <cstring>
#include <strings.h>
#include <cstdlib>

// int socket(int domain, int type, int protocal)
// int bind(int sockfd, const struct sockaddr* addr, socklen_t addrlen)

using std::cout;
using std::cerr;
using std::endl;

namespace ns_server
{

const static uint16_t default_port = 8989;



class UdpServer
{
public:
    UdpServer(uint16_t port = default_port)
        : _port(port)
    {
        cout << "Server Port:" << _port << endl;
    }
    ~UdpServer()
    {
    }

    void InitServer()
    {
        // 1.创建套接字，本质上是打开网络[文件]
        _sock = socket(AF_INET, SOCK_DGRAM, 0);
        if (_sock < 0)
        {
            cerr << "Create socket error: " << strerror(errno) << endl;
            exit(SOCKET_ERR);
        }
        cout << "Create socket success, fd=" << _sock << endl;

        // 2.给服务器绑定ip,port
        struct sockaddr_in local;
        bzero(&local, sizeof(local)); //清零
        local.sin_family = AF_INET;
        local.sin_port = htons(_port); //主机序列转网络序列
        // in_addr_t inet_addr(const char* cp)
        // local.sin_addr.s_addr = inet_addr(_ip.c_str()); // 字符串转4字节整数、主机序列转网络序列
        local.sin_addr.s_addr = INADDR_ANY; // 云服务器自动绑定任意ip
        // 绑定
        if(bind(_sock, (struct sockaddr*)&local, sizeof(local)) != 0)
        {
            cerr << "Bind socket error: "<< strerror(errno) << endl;
            exit(BIND_ERR);
        }
        cout << "Bind success "  << "\n";
    }

    //ssize_t recvfrom(int scokfd, void*buf, size_t len,int flags, struct sockaddr* src_addr, socklen_t* addrlen)
    //返回值是实际读取的长度
    //后两个参数是让你知道是谁给你发的消息。即客户端的ip+port
    //ssize_t sendto(int sockfd, const void*buf,size_t len,int flags,const struct sockaddr* dest_addr, socklen_t addrlen)
    void Start()
    {
        char buf[1024];
        while (true)
        {
            // 收消息
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer); // 这里必须写好大小sizeof(peer)
            int n = recvfrom(_sock, buf, sizeof(buf) - 1, 0, (struct sockaddr*)&peer, &len);
            if(n > 0) //读取成功
                buf[n] = '\0';
            else
                continue; //继续读取

            cout << "[Get a message From " << inet_ntoa(peer.sin_addr) << "-" << ntohs(peer.sin_port) << "]:: " << buf << endl;

            // 发消息
            // sendto(_sock, buf, strlen(buf), 0, (struct sockaddr *)&peer, sizeof(peer));

        }
    }

private:
    int _sock; // 文件描述符
    uint16_t _port; // 端口
    // std::string _ip; //云服务器，ip不要了
};
} // end ns_server